package com.yfbao.web.gateway.ops;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yfbao.web.gateway.router.RequestRouter;
import com.yfbao.web.gateway.utils.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

@Service
@Slf4j
public class FastApiProxyService {

    private final OkHttpClient okHttpClient;
    private final RequestRouter requestRouter;

    private final ObjectMapper objectMapper;
    //todo: 初始化时需要赋值
    private String baseUrl = "";
    private static Cache<String, String> tokenCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS)
            .maximumSize(10)
            .recordStats().build();

    public FastApiProxyService(OkHttpClient okHttpClient,
                               RequestRouter requestRouter,ObjectMapper objectMapper) {
        this.okHttpClient = okHttpClient;
        this.requestRouter = requestRouter;
        this.objectMapper = objectMapper;

    }

    /**
     * 代理请求到FastAPI服务 - 主要方法
     */
    public ResponseEntity<Object> proxyRequest(HttpServletRequest request, String requestBody) {
        try {
            // 1. 构建目标URL
            String targetUrl = buildTargetUrl(request);

            // 2. 创建OKHttp请求
            Request okHttpRequest = createOkHttpRequest(request, targetUrl, requestBody);

            // 3. 执行同步请求
            try (Response okHttpResponse = okHttpClient.newCall(okHttpRequest).execute()) {
                // 4. 转换为Spring ResponseEntity
                return convertOkHttpResponse(okHttpResponse);
            }

        } catch (SocketTimeoutException e) {
            log.error("请求FastAPI超时: {}", e.getMessage());
            return createErrorResponse(HttpStatus.GATEWAY_TIMEOUT, "后端服务响应超时");
        } catch (IOException e) {
            log.error("网络通信错误: {}", e.getMessage());
            return createErrorResponse(HttpStatus.BAD_GATEWAY, "网络通信错误");
        } catch (Exception e) {
            log.error("代理请求到FastAPI失败: {}", e.getMessage(), e);
            return createErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, "后端服务暂时不可用");
        }
    }

    /**
     * 异步代理请求（可选）
     */
    public CompletableFuture<ResponseEntity<Object>> proxyRequestAsync(HttpServletRequest request,
                                                                       String requestBody) {
        CompletableFuture<ResponseEntity<Object>> future = new CompletableFuture<>();

        try {
            String targetUrl = buildTargetUrl(request);
            Request okHttpRequest = createOkHttpRequest(request, targetUrl, requestBody);

            okHttpClient.newCall(okHttpRequest).enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {
                    try {
                        ResponseEntity<Object> result = convertOkHttpResponse(response);
                        future.complete(result);
                    } catch (Exception e) {
                        future.completeExceptionally(e);
                    } finally {
                        if (response != null) {
                            response.close();
                        }
                    }
                }

                @Override
                public void onFailure(Call call, IOException e) {
                    future.complete(createErrorResponse(HttpStatus.BAD_GATEWAY, e.getMessage()));
                }
            });

        } catch (Exception e) {
            future.complete(createErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()));
        }

        return future;
    }

    /**
     * 构建目标URL
     */
    private String buildTargetUrl(HttpServletRequest request) {
        String path = request.getRequestURI();
        String queryString = request.getQueryString();

        String targetUrl = requestRouter.buildFastApiUrl(path);

        if (queryString != null && !queryString.isEmpty()) {
            targetUrl += "?" + queryString;
        }

        return targetUrl;
    }

    /**
     * 创建OKHttp请求
     */
    private Request createOkHttpRequest(HttpServletRequest servletRequest,
                                        String url, String requestBody) {
        Request.Builder requestBuilder = new Request.Builder().url(url);

        // 设置HTTP方法
        String method = servletRequest.getMethod().toUpperCase();
        switch (method) {
            case "GET":
                requestBuilder.get();
                break;
            case "POST":
                requestBuilder.post(createRequestBody(servletRequest, requestBody));
                break;
            case "PUT":
                requestBuilder.put(createRequestBody(servletRequest, requestBody));
                break;
            case "DELETE":
                requestBuilder.delete(createRequestBody(servletRequest, requestBody));
                break;
            case "PATCH":
                requestBuilder.patch(createRequestBody(servletRequest, requestBody));
                break;
            case "HEAD":
                requestBuilder.head();
                break;
            default:
                throw new IllegalArgumentException("不支持的HTTP方法: " + method);
        }

        // 设置请求头
        setRequestHeaders(requestBuilder, servletRequest);

        return requestBuilder.build();
    }

    /**
     * 创建请求体
     */
    private RequestBody createRequestBody(HttpServletRequest request, String requestBody) {
        String contentType = getContentType(request);
        MediaType mediaType = MediaType.parse(contentType);

        if (requestBody == null) {
            return RequestBody.create(mediaType,new byte[0]);
        }

        return RequestBody.create(mediaType,requestBody.getBytes(StandardCharsets.UTF_8) );
    }

    /**
     * 设置请求头
     */
    private void setRequestHeaders(Request.Builder requestBuilder, HttpServletRequest servletRequest) {
        // 复制原始请求头
        Enumeration<String> headerNames = servletRequest.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            if (!shouldSkipHeader(headerName)) {
                Enumeration<String> headerValues = servletRequest.getHeaders(headerName);
                while (headerValues.hasMoreElements()) {
                    requestBuilder.addHeader(headerName, headerValues.nextElement());
                }
            }
        }

        // 设置特定的转发头
        requestBuilder.addHeader("X-Forwarded-For", getClientIp(servletRequest));
        requestBuilder.addHeader("X-Forwarded-Host", servletRequest.getServerName());
        requestBuilder.addHeader("X-Forwarded-Proto", servletRequest.getScheme());
        requestBuilder.addHeader("X-Real-IP", getClientIp(servletRequest));

        // 确保有User-Agent
        if (servletRequest.getHeader("User-Agent") == null) {
            requestBuilder.addHeader("User-Agent", "SpringBoot-Gateway/1.0");
        }
    }

    /**
     * 转换OKHttp响应为Spring ResponseEntity
     */
    private ResponseEntity<Object> convertOkHttpResponse(Response okHttpResponse) throws IOException {
        if (okHttpResponse == null || !okHttpResponse.isSuccessful()) {
            return handleErrorResponse(okHttpResponse);
        }

        // 获取响应头
        HttpHeaders headers = new HttpHeaders();
        okHttpResponse.headers().names().forEach(name ->
                headers.addAll(name, okHttpResponse.headers(name))
        );

        // 获取响应体
        ResponseBody responseBody = okHttpResponse.body();
        if (responseBody == null) {
            return new ResponseEntity<>(headers, HttpStatus.valueOf(okHttpResponse.code()));
        }

        // 根据Content-Type处理响应体
        String contentType = okHttpResponse.header("Content-Type");
        byte[] bodyBytes = responseBody.bytes();

        if (contentType != null && contentType.contains("application/json")) {
            // JSON响应
            Object body = parseJsonBody(bodyBytes);
            return new ResponseEntity<>(body, headers, HttpStatus.valueOf(okHttpResponse.code()));
        } else if (contentType != null && contentType.startsWith("text/")) {
            // 文本响应
            String body = new String(bodyBytes, StandardCharsets.UTF_8);
            return new ResponseEntity<>(body, headers, HttpStatus.valueOf(okHttpResponse.code()));
        } else {
            // 二进制响应
            return new ResponseEntity<>(bodyBytes, headers, HttpStatus.valueOf(okHttpResponse.code()));
        }
    }

    /**
     * 处理错误响应
     */
    private ResponseEntity<Object> handleErrorResponse(Response okHttpResponse) throws IOException {
        if (okHttpResponse == null) {
            return createErrorResponse(HttpStatus.BAD_GATEWAY, "后端服务无响应");
        }

        String errorMessage = "后端服务错误";
        if (okHttpResponse.body() != null) {
            try {
                String errorBody = okHttpResponse.body().string();
                if (errorBody != null && !errorBody.isEmpty()) {
                    errorMessage = extractErrorMessage(errorBody);
                }
            } catch (IOException e) {
                log.warn("读取错误响应体失败: {}", e.getMessage());
            }
        }

        return createErrorResponse(HttpStatus.valueOf(okHttpResponse.code()), errorMessage);
    }

    /**
     * 从错误响应体中提取错误信息
     */
    private String extractErrorMessage(String errorBody) {
        try {
            Map<String, Object> errorMap = objectMapper.readValue(errorBody, Map.class);
            if (errorMap.containsKey("message")) {
                return errorMap.get("message").toString();
            } else if (errorMap.containsKey("error")) {
                return errorMap.get("error").toString();
            }
        } catch (Exception e) {
            // 如果解析失败，返回原始错误体的前100个字符
            return errorBody.length() > 100 ? errorBody.substring(0, 100) + "..." : errorBody;
        }
        return "未知错误";
    }

    /**
     * 解析JSON响应体
     */
    private Object parseJsonBody(byte[] bodyBytes) {
        try {
            return objectMapper.readValue(bodyBytes, Object.class);
        } catch (Exception e) {
            log.warn("JSON响应解析失败，返回原始字符串");
            return new String(bodyBytes, StandardCharsets.UTF_8);
        }
    }

    /**
     * 获取内容类型
     */
    private String getContentType(HttpServletRequest request) {
        String contentType = request.getContentType();
        return contentType != null ? contentType : "application/json; charset=utf-8";
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String xff = request.getHeader("X-Forwarded-For");
        if (xff != null && !xff.isEmpty()) {
            return xff.split(",")[0].trim();
        }
        return request.getRemoteAddr();
    }

    /**
     * 判断是否跳过某个请求头
     */
    private boolean shouldSkipHeader(String headerName) {
        return headerName.equalsIgnoreCase("host") ||
                headerName.equalsIgnoreCase("content-length") ||
                headerName.equalsIgnoreCase("accept-encoding");
    }

    /**
     * 创建错误响应
     */
    private ResponseEntity<Object> createErrorResponse(HttpStatus status, String message) {
        Map<String, Object> error = new HashMap<>();
        error.put("error", true);
        error.put("message", message);
        error.put("timestamp", System.currentTimeMillis());
        error.put("status", status.value());

        return new ResponseEntity<>(error, status);
    }

    /**
     * 获取连接池统计信息（监控用）
     */
    public Map<String, Object> getConnectionPoolStats() {
        ConnectionPool connectionPool = okHttpClient.connectionPool();

        Map<String, Object> stats = new HashMap<>();
        stats.put("connectionCount", connectionPool.connectionCount());
        stats.put("idleConnectionCount", connectionPool.idleConnectionCount());
        stats.put("requestCount", getRequestCount()); // 需要自定义统计

        return stats;
    }

    private AtomicLong requestCount = new AtomicLong(0);

    private long getRequestCount() {
        return requestCount.get();
    }


    /************************单独封装请求*************************************/

    /**
     * GET 请求
     */
    public <T> T get(String path, Class<T> responseType, Map<String, String> queryParams) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(CommonUtil.buildUrl(baseUrl, path)).newBuilder();

        if (queryParams != null) {
            queryParams.forEach(urlBuilder::addQueryParameter);
        }
        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .get()
                .build();

        return executeRequest(request, responseType);
    }

    /**
     * POST 请求 - JSON 数据
     */
    public <T, R> T post(String path, R requestBody, Class<T> responseType) {
        String jsonBody = toJson(requestBody);
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonBody);

        Request request = new Request.Builder()
                .url(CommonUtil.buildUrl(baseUrl ,path))
                .post(body)
                .build();

        return executeRequest(request, responseType);
    }

    /**
     * POST 请求 - 表单数据
     */
    public <T> T postForm(String path, Map<String, String> formData, Class<T> responseType) {
        FormBody.Builder formBuilder = new FormBody.Builder();
        if (formData != null) {
            formData.forEach(formBuilder::add);
        }
        Request request = new Request.Builder()
                .url(CommonUtil.buildUrl(baseUrl ,path))
                .post(formBuilder.build())
                .build();

        return executeRequest(request, responseType);
    }

    /**
     * PUT 请求
     */
    public <T, R> T put(String path, R requestBody, Class<T> responseType) {
        String jsonBody = toJson(requestBody);
        RequestBody body = RequestBody.create( MediaType.parse("application/json; charset=utf-8"),jsonBody);

        Request request = new Request.Builder()
                .url(CommonUtil.buildUrl(baseUrl ,path))
                .put(body)
                .build();

        return executeRequest(request, responseType);
    }

    /**
     * DELETE 请求
     */
    public <T> T delete(String path, Class<T> responseType) {
        Request request = new Request.Builder()
                .url(CommonUtil.buildUrl(baseUrl ,path))
                .delete()
                .build();

        return executeRequest(request, responseType);
    }

    /**
     * 执行请求
     */
    private <T> T executeRequest(Request request, Class<T> responseType) {
        try (Response response = okHttpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("请求失败，状态码: " + response.code());
            }

            ResponseBody responseBody = response.body();
            if (responseBody == null) {
                throw new RuntimeException("响应体为空");
            }

            String responseString = responseBody.string();
            log.debug("响应内容: {}", responseString);

            return objectMapper.readValue(responseString, responseType);

        } catch (IOException e) {
            log.error("请求执行失败 - URL: {}", request.url(), e);
            throw new RuntimeException("网络请求失败", e);
        }
    }

    /**
     * 异步 GET 请求
     */
    public <T> CompletableFuture<T> getAsync(String path, Class<T> responseType,
                                             Map<String, String> queryParams) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(CommonUtil.buildUrl(baseUrl ,path)).newBuilder();

        if (queryParams != null) {
            queryParams.forEach(urlBuilder::addQueryParameter);
        }

        Request request = new Request.Builder()
                .url(urlBuilder.build())
                .get()
                .build();

        return executeRequestAsync(request, responseType);
    }


//    private Request tokenInterceptor(Request request){
//        HttpUrl url = request.url();
//        //判断url 是否为白名单请求，如果白名单，则直接往后继续请求，否则执行下面检查token逻辑
//
//        String s = request.headers().get("token");
//        if(StrUtil.isBlank(s)){
//            String token = getToken();
////            Headers.Builder headerBuilder = request.headers().newBuilder().add("token", token);
//            request = request.newBuilder().addHeader("token", token).build();
//        }
//        return request;
//    }
    /**
     * 异步执行请求
     */
    private <T> CompletableFuture<T> executeRequestAsync(Request request, Class<T> responseType) {
        CompletableFuture<T> future = new CompletableFuture<>();
//        Request newRequest = tokenInterceptor(request);
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    if (!response.isSuccessful()) {
                        future.completeExceptionally(
                                new RuntimeException("请求失败，状态码: " + response.code())
                        );
                        return;
                    }

                    ResponseBody responseBody = response.body();
                    if (responseBody == null) {
                        future.completeExceptionally(new RuntimeException("响应体为空"));
                        return;
                    }

                    String responseString = responseBody.string();
                    T result = objectMapper.readValue(responseString, responseType);
                    future.complete(result);

                } catch (Exception e) {
                    future.completeExceptionally(e);
                }
            }

            @Override
            public void onFailure(Call call, IOException e) {
                future.completeExceptionally(e);
            }
        });

        return future;
    }

    private String toJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON序列化失败", e);
        }
    }



}
